/**
 * Drag 拖动
 *
 */
;
// 记录元素定位信息
var locate_info = [];
(function($, window, document, undefined) {
    'use strict';
    // 默认参数
    var Data = {
        defaults: {
            class: '', // 唯一
            spacing: '10', // 间距
            revert: 'index', // 返回类型 id index
            range: true, // 是否允许拖动超出区域
        }
    };
    // 插件引擎
    var Engine = {
        // 获取属性设置
        getAttrSettings: function($original) {
            let defaults = Data.defaults;
            var attrData = {};
            $.each(defaults, (key, val) => {
                if ($original.is('[data-' + key + ']')) {
                    var elAttr = $original.attr('data-' + key);
                    if (elAttr === 'true' || elAttr === 'false') { elAttr = elAttr === 'true'; }
                    if (elAttr === "") { elAttr = defaults[key]; }
                    attrData[key] = elAttr;
                }
            })
            return attrData;
        },
        // 初始化
        initialize: function($original, userSettings) {
            let self = this,
                settings = $.extend(true, {}, userSettings),
                attrSettings = self.getAttrSettings($original);
            settings = $.extend(settings, attrSettings);
            Build.build($original, settings);

            // 事件方法
            Binds.bind($original, locate_info, settings)
            return $original
        },
        // 检查目标
        controlTarget: function($target, controls) {
            // 初始化时是否是drag
            if ($.inArray('isDrag', controls) !== -1 && !$target.hasClass('drag')) {
                console.error('Drag | initialization failed，Invalid input element');
                console.log($target[0]);
                return false;
            }
            // 是否唯一
            if ($.inArray('isSingle', controls) !== -1 && $target.length > 1) {
                console.error('Drag | Can only be called on a single element');
                console.log($target[0]);
                return false;
            }
            // 初始化时是否包含拖动元素
            if ($.inArray('drag_elemt', controls) !== -1 && $target.children().length < 1) {
                console.error('Drag | No "drag_item" drag element');
                console.log($target[0]);
                return false;
            }
            return true;
        },
        // 检查values
        controlValues: function($target, values) {
            if (!(values instanceof Object)) {
                console.error('values parameter is not a valid Object');
                console.log($target[0]);
                console.log(values);
                return false;
            }
            return true;
        },
        del: function($original, valObjs) {
            let self = this,
                aLi = $original.children(),
                spacing = parseInt($original.data('spacing')), // 边距
                column = Math.floor($original.width() / (aLi.outerWidth() + spacing * 2)), // 总列数
                aLi_height = aLi.outerHeight() + spacing * 2, // 拖动元素高度
                aLi_width = aLi.outerWidth() + spacing * 2, // 拖动元素宽度
                rows = Math.ceil(aLi.length / column); // 总行数
            aLi.each(function(index, el) {
                let t = $(this);
                if (t.attr('index') > valObjs.index) {
                    let idx = t.attr('index'),
                        t_row = Math.ceil(idx / column - 1),
                        t_col = idx % column == 0 ? column - 1 : idx % column - 1,
                        left = t_col * aLi_width + spacing,
                        top = t_row * aLi_height + spacing;
                    t.attr('index', idx - 1);
                    t.css({
                        left: left + 'px',
                        top: top + 'px',
                        margin: '0px',
                        position: 'absolute'
                    })
                } else {
                    t.css({
                        margin: '0px',
                        position: 'absolute'
                    })
                }
            });
            // 父级的高度
            $original.css('height', aLi_height * rows + 'px')
        },
        set: function($original, valObjs) {
            let self = this,
                oUl = document.querySelector("." + $original.data('class')),
                aLi = oUl.querySelectorAll(".drag_item"),
                obj, oNear;
            for (var i = 0; i < aLi.length; i++) {
                if (aLi[i].getAttribute("index") == valObjs.start) {
                    obj = aLi[i];
                }
                if (aLi[i].getAttribute("index") == valObjs.end) {
                    oNear = aLi[i];
                }
            }
            clearInterval(oNear.timer);
            clearInterval(obj.timer);
            Binds.startMove(oNear, locate_info[valObjs.start]);
            Binds.startMove(obj, locate_info[valObjs.end]);
            // 返回当前切换
            if ($original.data('revert') === 'id') {
                $(document).trigger('drag:' + $original.data('class'), [$(obj).data('id'), $(oNear).data('id')]);
            }
            if ($original.data('revert') === 'index') {
                $(document).trigger('drag:' + $original.data('class'), [valObjs.start, valObjs.end]);
            }
            //交换index
            obj.setAttribute("index", valObjs.end);
            oNear.setAttribute("index", valObjs.start);
        },
        reset: function($original) {
            $original.children().css({
                position: 'static',
                margin: $original.data('spacing') + 'px'
            });
        }
    }
    var Build = {
        build: function($original, settings) {
            let self = this,
                oUl = document.querySelector("." + $original.data('class')),
                aLi = oUl.querySelectorAll(".drag_item"),
                column = Math.floor(oUl.offsetWidth / (aLi[0].offsetWidth + parseInt(settings.spacing) * 2)),
                aLi_height = aLi[0].offsetHeight + parseInt(settings.spacing) * 2,
                rows = Math.ceil(aLi.length / column);

            // console.log(aLi)
            // 重新定位拖动元素
            for (var i = 0; i < aLi.length; i++) {
                aLi[i].style.margin = settings.spacing + 'px';

                let t, l;

                if (aLi[i].classList.contains('nail_end')) {
                    t = aLi[i].offsetTop;
                    l = aLi[i].offsetLeft;
                } else {
                    t = aLi[i].style.top ? parseInt(aLi[i].style.top) : aLi[i].offsetTop;
                    l = aLi[i].style.left ? parseInt(aLi[i].style.left) : aLi[i].offsetLeft;
                }

                if (!aLi[i].getAttribute('index')) {
                    // aLi[i].index = i;
                    locate_info[i] = { left: l, top: t };
                    aLi[i].setAttribute('index', i)
                }
                // console.log(aLi[i].index)
                // console.log('---------------------')
                aLi[i].style.zIndex = 5;
                aLi[i].style.top = t + "px";
                aLi[i].style.left = l + "px";
            }
            for (var b = 0; b < aLi.length; b++) {
                aLi[b].style.position = "absolute";
                aLi[b].style.margin = 0;
            }
            // 父级的高度
            oUl.style.height = aLi_height * rows + 'px';
            if (!$original.data('spacing')) {
                $original.data('spacing', settings.spacing)
            }
        }
    }
    // 事件
    var minZindex = 5;
    var Binds = {
        // 初始化
        bind: function($original, locate_info, settings) {
            let self = this,
                oUl = document.querySelector("." + settings.class),
                aLi = oUl.querySelectorAll(".drag_item");
            for (var i = 0; i < aLi.length; i++) {
                // 点击事件
                if (aLi[i].removeEventListener) { // 所有浏览器，除了 IE 8 及更早IE版本
                    aLi[i].removeEventListener("mousemove", function() {});
                } else if (x.detachEvent) { // IE 8 及更早IE版本
                    aLi[i].detachEvent("onmousemove", function() {});
                }
                aLi[i].addEventListener('mousedown', self.mousedown.bind(this, locate_info, $original, settings));
            }
        },
        // 点击事件
        mousedown: function(locate_info, $original, settings, event) {
            // 阻止事件默认行为，解决拖动打开新页面
            event.stopPropagation()
            event.preventDefault()

            // 禁用图片的默认行为，解决图片预览时冲突
            $original.find('img').on('click', function(e) {
                e.preventDefault();
                e.stopPropagation();
            })

            let self = this,
                oUl = document.querySelector("." + settings.class),
                aLi = oUl.querySelectorAll(".drag_item"),
                obj;
            var disX = 0,
                disY = 0;
            // 判断是否是拖动元素
            if (event.target.classList.contains('drag_item')) {
                obj = event.target
            } else {
                obj = $(event.target).parents('.drag_item')[0]
            }

            // 判断是否可以拖动
            if (obj.classList.contains('forbid') || $(event.target).parents('.cancel').length > 0 || $(event.target).hasClass('cancel')) {
                return false;
            }

            var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
            var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
            obj.style.zIndex = minZindex++;
            //当鼠标按下时计算鼠标与拖拽对象的距离
            disX = event.clientX + scrollLeft - obj.offsetLeft;
            disY = event.clientY + scrollTop - obj.offsetTop;
            document.onmousemove = function(event) {
                //当鼠标拖动时计算div的位置
                var l = event.clientX - disX + scrollLeft;
                var t = event.clientY - disY + scrollTop;
                obj.style.left = l + "px";
                obj.style.top = t + "px";

                for (var i = 0; i < aLi.length; i++) {
                    aLi[i].classList.remove('active');
                }
                var oNear = self.findMin(obj, aLi);
                if (oNear && !oNear.classList.contains('forbid')) {
                    oNear.classList.add('active');
                }
            }
            document.onmouseup = function() {
                document.onmousemove = null; //当鼠标弹起时移出移动事件
                document.onmouseup = null; //移出up事件，清空内存
                //检测是否普碰上，在交换位置
                var oNear = self.findMin(obj, aLi);
                if (oNear && !oNear.classList.contains('forbid')) {
                    oNear.classList.remove('active');
                    oNear.style.zIndex = minZindex++;
                    obj.style.zIndex = minZindex++;
                    self.startMove(oNear, locate_info[obj.getAttribute('index')]);
                    self.startMove(obj, locate_info[oNear.getAttribute('index')]);
                    // 返回切换元素位置 obj起始位置 onear结束位置
                    let start = obj.getAttribute('index'),
                        end = oNear.getAttribute('index'),
                        start_id = obj.dataset.id && obj.dataset.id !== undefined ? obj.dataset.id : '',
                        end_id = oNear.dataset.id && oNear.dataset.id !== undefined ? oNear.dataset.id : '';

                    // 返回当前切换
                    if (settings.revert === 'id') {
                        $(document).trigger('drag:' + settings.class, [start_id, end_id]);
                    }
                    if (settings.revert === 'index') {
                        $(document).trigger('drag:' + settings.class, [start, end]);
                    }

                    //交换index
                    obj.setAttribute('index', end);
                    oNear.setAttribute('index', start);
                } else {
                    self.startMove(obj, locate_info[obj.getAttribute('index')]);
                }
            }
            clearInterval(obj.timer);
            return false; //低版本出现禁止符号
        },
        // 移动位置
        startMove: function(obj, json) {
            let self = this;
            clearInterval(obj.timer);
            obj.timer = setInterval(function() {
                var isStop = true;
                for (var attr in json) {
                    var iCur = 0;
                    if (attr == "opacity") { iCur = parseInt(parseFloat(self.getStyle(obj, attr)) * 100); } else { iCur = parseInt(self.getStyle(obj, attr)); }
                    var ispeed = (json[attr] - iCur) / 8;
                    ispeed = ispeed > 0 ? Math.ceil(ispeed) : Math.floor(ispeed);
                    if (iCur != json[attr]) { isStop = false; }
                    if (attr == "opacity") {
                        obj.style.filter = "alpha:(opacity:" + (json[attr] + ispeed) + ")";
                        obj.style.opacity = (json[attr] + ispeed) / 100;
                    } else { obj.style[attr] = iCur + ispeed + "px"; }
                }
                if (isStop) { clearInterval(obj.timer); }
            }, 30);
        },
        // 获取属性
        getStyle: function(obj, attr) {
            return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj, false)[attr];
        },
        // 找到距离最近的
        findMin: function(obj, aLi) {
            let self = this;
            var minDis = 999999999;
            var minIndex = -1;
            for (var i = 0; i < aLi.length; i++) {
                if (obj == aLi[i]) continue;
                if (self.colTest(obj, aLi[i])) {
                    var dis = self.getDis(obj, aLi[i]);
                    if (dis < minDis) {
                        minDis = dis;
                        minIndex = i;
                    }
                }
            }
            if (minIndex == -1) {
                return null;
            } else {
                return aLi[minIndex];
            }
        },
        //碰撞检测
        colTest: function(obj1, obj2) {
            var t1 = obj1.offsetTop;
            var r1 = obj1.offsetWidth + obj1.offsetLeft;
            var b1 = obj1.offsetHeight + obj1.offsetTop;
            var l1 = obj1.offsetLeft;

            var t2 = obj2.offsetTop;
            var r2 = obj2.offsetWidth + obj2.offsetLeft;
            var b2 = obj2.offsetHeight + obj2.offsetTop;
            var l2 = obj2.offsetLeft;

            if (t1 > b2 || r1 < l2 || b1 < t2 || l1 > r2) {
                return false;
            } else {
                return true;
            }
        },
        // 勾股定理求距离
        getDis: function(obj1, obj2) {
            var a = obj1.offsetLeft - obj2.offsetLeft;
            var b = obj1.offsetTop - obj2.offsetTop;
            return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
        }
    }
    // 方法操作
    var Methods = {
        // 初始化
        init: function(opts) {
            return this.each(function() {
                let settings = $.extend(true, {}, Data.defaults, opts);
                let $original = $(this);
                // class 唯一性
                $original.addClass($original.data('class'))
                if (Engine.controlTarget($original, ['isDrag'])) {
                    if (Engine.controlTarget($('.' + $original.data('class')), ['isSingle'])) {
                        if (Engine.controlTarget($('.' + $original.data('class')), ['drag_elemt'])) {
                            Engine.initialize($original, settings);
                        }
                    }
                }
            });
        },
        // 设置
        set: function(values) {
            return this.each(function() {
                var $original = $(this);
                if (Engine.controlTarget($('.' + $original.data('class')), ['isSingle'])) {
                    if (Engine.controlValues(this, values)) {
                        Engine.set($original, values);
                    }
                }
            });
        },
        // 重置
        reset: function(values) {
            return this.each(function() {
                var $original = $(this);
                if (Engine.controlTarget($('.' + $original.data('class')), ['isSingle'])) {
                    Engine.reset($original);
                }
            });
        },
        del: function(values) {
            return this.each(function() {
                var $original = $(this);
                if (Engine.controlTarget($('.' + $original.data('class')), ['isSingle'])) {
                    if (Engine.controlValues(this, values)) {
                        Engine.del($original, values);
                    }
                }
            });
        }
    }
    // 使用插件
    $.fn.Drag = function(options) {
        if (this.length < 1) { return; }
        // console.log(options)
        // 判断是什么操作
        if (Methods[options]) {
            // 传入进来的具有length属性的第一个参数arguments转换为数组，再调用它的slice（截取）方法
            var slicedArguments = Array.prototype.slice.call(arguments, 1);
            return Methods[options].apply(this, slicedArguments);
        } else if (typeof options === 'object' || !options) {
            return Methods.init.apply(this, arguments);
        } else {
            console.error('Drag | Call error');
            console.log(this);
        }
    };

})(jQuery, window, document);